import { TransformNode } from "@babylonjs/core/Meshes/transformNode";
import { DefaultStage } from "../../default-stage";
import { Model } from "../model";
import { RawAssetsUrl } from "../../../raw-assets-info";
import { Vector3 } from "@babylonjs/core/Maths/math.vector";
import { Axis } from "@babylonjs/core/Maths/math.axis";
import { AnimationFrame, Texture } from "babylon-lib/index";
import { State } from 'babylon-lib/misc/state';
import { RenderOrder } from "babylon-lib/misc/render-order";
import * as Data from '../../../data/data';
import { Landscape } from "../landscape/landscape";
import { Color3 } from "@babylonjs/core/Maths/math.color";
import { MeshBuilder } from "@babylonjs/core/Meshes/meshBuilder";
import { Plane } from "@babylonjs/core/Maths/math.plane";
import { Ray } from "@babylonjs/core/Culling/ray";
import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial";
import { AbstractCharacter } from "./abstract-character";
import { CrossImage } from 'babylon-lib/texture/icon-image/cross-image';
import { WebXRCamera } from "@babylonjs/core";


enum STATE {
    RIGHT_BOMB_IN_PLACE,
    RIGHT_BOMB_DROP,
    RIGHT_BOMB_DESTROY,
    LEFT_BOMB_IN_PLACE,
    LEFT_BOMB_DROP,
    LEFT_BOMB_DESTROY,
    RELOADING,
};

class UAV extends AbstractCharacter {

    private _sampleReq = {};
    private _reloadReq = {};
    private _state = new State(STATE.RIGHT_BOMB_IN_PLACE, STATE.LEFT_BOMB_IN_PLACE);
    private _reloadTime = 25000;
    private _count = 0;
    private _countReq = {};
    private _ray = new Ray(new Vector3(0, 0, 0), new Vector3(1, 0, 0), 5000);
    private _plane = Plane.FromPositionAndNormal(new Vector3(0, 0, 0), new Vector3(0, 1, 0));
    private _tv0 = new Vector3();
    private _tv1 = new Vector3();
    private _tv2 = new Vector3();
    private _detectReq = {};
    private _maxDistance = 5000;
    private _targetMark!: TransformNode;
    private _explodeMark!: TransformNode;
    private _targetPoint = new Vector3(2000, 0, 2000);
    private _explodePoint = new Vector3(2000, 0, 2000);

    public inertia = new Vector3();

    constructor(stage: DefaultStage) {
        super(stage);
        this.setModel(stage);
        this.setTargetMark(stage);
        this.setExplodeMark(stage);
        this.sampling(stage);
    }

    public recordTarget(): void {
        this._targetPoint.set(Data.coordinateX.value, 0, Data.coordinateZ.value);
        this._explodePoint.set(Data.coordinateX.value, 0, Data.coordinateZ.value);
        Data.offsetX.value = 0;
        Data.offsetZ.value = 0;
    }

    public recordExplode(): void {
        this._explodePoint.set(Data.coordinateX.value, 0, Data.coordinateZ.value);
        Data.offsetX.value = this._explodePoint.x - this._targetPoint.x;
        Data.offsetZ.value = this._explodePoint.z - this._targetPoint.z;
    }

    private focusCoordinate(): void {
        const cam = this.stage.mainCamera;
        const ray = this._ray;
        ray.origin.copyFrom(cam.globalPosition);
        cam.getDirectionToRef(Axis.Z, this._tv0);
        if (!(cam instanceof WebXRCamera)) this._tv0.negateInPlace();
        ray.direction.copyFrom(this._tv0);
        const dis = ray.intersectsPlane(this._plane);
        if (dis && dis < this._maxDistance) {
            this._tv0.scaleInPlace(dis);
        } else {
            this._tv0.set(0, 0, 0);
        }
        Data.coordinateX.value = this._tv0.x;
        Data.coordinateZ.value = this._tv0.z;
        Data.distance.value = (dis && dis < this._maxDistance) ? dis : 0;
    }

    private sampling(stage: DefaultStage): void {
        AnimationFrame.cancel(this._countReq);
        const prePos = new Vector3();
        const curPos = new Vector3();
        const ext = Landscape.zoneExtend;
        AnimationFrame.request(() => {
            curPos.copyFrom(this._container.getAbsolutePosition());
            this.inertia.copyFrom(curPos).subtractInPlace(prePos);
            prePos.copyFrom(curPos);

            if (curPos.x < -ext || curPos.x > ext || curPos.z < -ext || curPos.z > ext) {
                AnimationFrame.throttleByTime(this._countReq, 1000, () => {
                    const c = 10 - this._count;
                    Data.failedCount.value = Math.max(c, 0);
                    if (c <= 0) {
                        Data.taskStatus.value = Data.taskState.interrupt;
                        Data.gameOn.value = false;
                    }
                    this._count++;
                }, true);
            } else {
                this._count = 0;
                Data.failedCount.value = 10;
            }

            AnimationFrame.throttleByTime(this._detectReq, 200, () => {
                this.focusCoordinate();
                this.updateMark();
            }, true);

        }, 16, 200, this._sampleReq);
    }

    private updateMark(): void {
        const v = this._tv0.copyFrom(this._container.position);
        const t = this._tv1.copyFrom(this._targetPoint);
        t.subtractInPlace(v).normalize().scaleInPlace(75).addInPlace(v);
        this._targetMark.setAbsolutePosition(t);

        const e = this._tv2.copyFrom(this._explodePoint);
        e.subtractInPlace(v).normalize().scaleInPlace(75).addInPlace(v);
        this._explodeMark.setAbsolutePosition(e);
    }

    protected setModel(stage: DefaultStage): void {
        Model.wurenji.parent = this._container;
        Model.wurenji.position.set(0, 0, 0);
        Model.wurenji.scaling.set(5, 5, 5);
    }

    private setTargetMark(stage: DefaultStage): void {
        const m = MeshBuilder.CreatePlane('uav-target-mark', { size: 3 }, stage.mainScene);
        const texture = stage.loader(stage.mainScene).getTextureTaskInfo(RawAssetsUrl.textureTarget)?.texture!;
        const mat = new StandardMaterial('uav-target-mark-material', stage.mainScene);
        mat.opacityTexture = texture;
        mat.transparencyMode = 1;
        mat.alphaCutOff = 0.5;
        mat.emissiveColor = Color3.FromHexString('#00ff00');
        mat.disableLighting = true;
        m.material = mat;
        m.billboardMode = TransformNode.BILLBOARDMODE_ALL;
        m.renderingGroupId = RenderOrder.id(Data.orders.sceneUiBack);
        const ctn = new TransformNode('uav-target-mark-container', stage.mainScene);
        m.setParent(ctn);
        m.position.set(0, 0, 0);
        ctn.setParent(this._container);
        this._targetMark = ctn;
    }

    private setExplodeMark(stage: DefaultStage): void {
        const m = MeshBuilder.CreatePlane('uav-explode-mark', { size: 1.5 }, stage.mainScene);
        const texture = CrossImage(1, '#00ff00');
        const mat = new StandardMaterial('uav-explode-mark-material', stage.mainScene);
        mat.opacityTexture = new Texture(texture, stage.mainScene);
        mat.transparencyMode = 1;
        mat.alphaCutOff = 0.5;
        mat.emissiveColor = Color3.FromHexString('#00ff00');
        mat.disableLighting = true;
        m.material = mat;
        m.billboardMode = TransformNode.BILLBOARDMODE_ALL;
        m.renderingGroupId = RenderOrder.id(Data.orders.sceneUiBack);
        const ctn = new TransformNode('uav-explode-mark-container', stage.mainScene);
        m.setParent(ctn);
        m.position.set(0, 0, 0);
        ctn.setParent(this._container);
        this._explodeMark = ctn;
    }

}


export { UAV };